﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;

namespace IV.Core
{
    /// <summary>
    /// 封装程序配置
    /// </summary>
    public class AppSettings
    {
        /// <summary>
        /// 机台相关配置
        /// </summary>
        public static XStore LocalSettings { get; private set; }
        /// <summary>
        /// 产品相关配置
        /// </summary>
        public static XStore SpecSettings { get; private set; }
        /// <summary>
        /// 加载机台配置
        /// </summary>
        /// <param name="filename"></param>
        static public void LoadLocalSettings(string filename = "settings.xml")
        {
            LocalSettings = XStore.FromFile(filename);
            // 从机配置中找到当前产品配置路径
            var SpecSettingsFile = LocalSettings.GetScope("App").Default("SpecSettings", "Spec.xml").Value<string>("SpecSettings");
            SpecSettings = XStore.FromFile(SpecSettingsFile);
        }
        /// <summary>
        /// 加载产品配置
        /// </summary>
        /// <param name="filename"></param>
        static public void LoadSpecSttings(string filename)
        {
            SpecSettings = XStore.FromFile(filename);
            LocalSettings.GetScope("App").Value<string>("SpecSettings", filename);
            LocalSettings.Save();
        }

        static AppSettings()
        {
            LoadLocalSettings();
        }
    }

    /// <summary>
    /// 管理xml格式配置信息
    /// </summary>
    public class XStore
    {
        // 配置文件保存路径
        private string DocumentFileName = null;
        private XDocument Document;

        public XStore()
        {
            Document = new XDocument();
            Document.Add(new XElement("root"));
        }

        /// <summary>
        /// 从文件加载
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static XStore FromFile(string filename)
        {
            var store = new XStore();
            try
            {
                store.Document = XDocument.Load(filename);
                store.DocumentFileName = filename;
            }
            catch(FileNotFoundException)
            {
                // 如果文件不存在，创建缺省xml文件
                store.Document.Save(filename);
                store.DocumentFileName = filename;
            }
            catch (Exception e)
            {
                // DirectoryNotFoundException 或 XmlException
                //throw new Exception($"XStore Load {filename} failed: {e.Message}");
            }

            return store;
        }
        /// <summary>
        /// 保存配置文件
        /// </summary>
        /// <param name="filename"></param>
        public void Save()
        {
            _Save(DocumentFileName);
        }
        /// <summary>
        /// 永久保存配置到指定位置，并且改变文件路径
        /// </summary>
        /// <param name="filename"></param>
        public void SaveAs(string filename)
        {
            if (string.IsNullOrEmpty(filename))
                return;
            DocumentFileName = filename;
            _Save(filename);
        }
        /// <summary>
        /// 临时保存配置到指定位置，不改变文件路径
        /// </summary>
        /// <param name="filename"></param>
        public void SaveTo(string filename)
        {
            if (string.IsNullOrEmpty(filename))
                return;
            _Save(filename);
        }
        private void _Save(string filename)
        {
            if (!string.IsNullOrEmpty(filename))
            {
                try
                {
                    Document.Save(filename);
                }
                catch (Exception e)
                {
                    throw new Exception($"Save Confing fail: {e.Message}");
                }
            }
        }
        /// <summary>
        /// 获取xml文档中的元素
        /// </summary>
        /// <param name="path">子节点的多级路径，用.分隔</param>
        /// <returns></returns>
        public XScope GetScope(string path)
        {
            XElement root = Document.Root;
            if (string.IsNullOrEmpty(path))
                return new XScope(root);

            string[] tags = path.Split('.');
            XElement ele = root;
            for (int i = 0; i < tags.Length; i++)
            {
                var name = tags[i];
                try
                {
                    if (string.IsNullOrEmpty(name))
                        continue;
                    XElement childXEle = ele.Element(name);
                    if (childXEle == null)
                    {
                        childXEle = new XElement(name);
                        ele.Add(childXEle);
                    }
                    ele = childXEle;
                }
                catch (Exception) { }
            }
            return new XScope(ele);
        }
    }

    public class XScope
    {
        private readonly XElement Element;
        public XScope(XElement Element)
        {
            this.Element = Element;
        }
        public XScope(string name)
        {
            this.Element = new XElement(name);
        }
        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Key">属性名</param>
        /// <returns></returns>
        public T Value<T>(string Key)
        {
            XAttribute attr = Element.Attribute(Key);
            if (typeof(T) == typeof(string))
                return (T)Convert.ChangeType(attr?.Value, typeof(T));

            if (attr != null)
            {
                string attrValue = attr.Value;
                Type t = typeof(T);
                if (t.IsEnum)
                {
                    try
                    {
                        return (T)Enum.Parse(t, attrValue);
                    }
                    catch
                    {
                        return default(T);
                    }
                }

                var tryParse = t.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder
                        , new Type[] { attrValue.GetType(), t.MakeByRefType() }
                        , new ParameterModifier[] { new ParameterModifier(2) });

                if (tryParse != null)
                {
                    var parameters = new object[] { attrValue, Activator.CreateInstance(t) };
                    bool success = (bool)tryParse.Invoke(null, parameters);
                    if (success)
                        return (T)parameters[1];
                }
                else
                {
                    var Parse = t.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder
                           , new Type[] { attrValue.GetType() }
                           , new ParameterModifier[] { new ParameterModifier(1) });
                    if (Parse != null)
                    {
                        var parameters = new string[] { attrValue };
                        try
                        {
                            var v = Parse.Invoke(null, parameters);
                            return (T)v;
                        }
                        catch { }
                    }
                }
            }
            return default;
        }
        /// <summary>
        /// 是否存在参数值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool HasValue(string key)
        {
            return Element.Attribute(key) != null;
        }
        /// <summary>
        /// 设置缺省参数值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public XScope Default<T>(string key, T defaultValue)
        {
            XAttribute attr = Element.Attribute(key);
            if (attr == null)
            {
                Element.SetAttributeValue(key, defaultValue);
            }
            return this;
        }
        /// <summary>
        /// 设置属性值，所有类型的值都是调ToString()方法转成string
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Key">属性名</param>
        /// <param name="Value">属性值</param>
        public void Value<T>(string Key, T Value)
        {
            Element.SetAttributeValue(Key, Value);
        }
        /// <summary>
        /// 获取一个子节点,如果没有则创建一个子节点
        /// </summary>
        /// <param name="Name">了节点名称</param>
        /// <returns></returns>
        public XScope Child(string Name)
        {
            var Ele = Element.Element(Name);
            if (Ele == null)
            {
                Ele = new XElement(Name);
                Element.Add(Ele);
            }
            return new XScope(Ele);
        }
        /// <summary>
        /// 获取第Index个子节点，如果没有则创建，index从0开始
        /// </summary>
        /// <param name="Index"></param>
        /// <returns></returns>
        public XScope Child(int Index)
        {
            int Count = Element.Elements().Count();
            if (Index >= Count)
            {
                for (int i = Count; i <= Index; i++)
                    Element.Add(new XElement("item"));
            }
            var Ele = Element.Elements().ElementAt(Index);
            return new XScope(Ele);
        }
        /// <summary>
        /// 获取全部子节点
        /// </summary>
        /// <returns></returns>
        public IEnumerable<XScope> Children()
        {
            return Element.Elements().Select(e => new XScope(e));
        }
        /// <summary>
        /// 将一个Scope添加到子节点中
        /// </summary>
        /// <param name="scope"></param>
        public void AddChild(XScope scope)
        {
            Element.Add(scope.Element);
        }
        /// <summary>
        /// 创建一个节点并添加到子节点中，并返回这个子节点
        /// </summary>
        /// <param name="name"></param>
        public XScope AddChild(string name)
        {
            var data = new XElement(name);
            Element.Add(data);
            return new XScope(data);
        }
        /// <summary>
        /// 在指定位置插入一个子节点
        /// </summary>
        /// <param name="index">插入后的子节点在列表中的位置，从0开始</param>
        /// <param name="scope"></param>
        public void InsertChild(int index, XScope scope)
        {
            var list = Element.Elements();
            var count = list.Count();
            if (count == 0)
            {
                Element.Add(scope.Element);
                return;
            }

            index = index >= count ? count - 1 : index;
            var pos = list.ElementAt(index);
            pos.AddBeforeSelf(scope.Element);
        }
        /// <summary>
        /// 删除节点自身（与父节点脱离关系）
        /// </summary>
        public void Remove()
        {
            if (Element.Parent != null)
            {
                Element.Remove();
            }
        }
        /// <summary>
        /// 删除全部子节点
        /// </summary>
        public void RemoveChildren()
        {
            Element.RemoveNodes();
        }
        /// <summary>
        /// 删除全部子节点及所有属性
        /// </summary>
        public void Clear()
        {
            Element.RemoveAll();
        }
        /// <summary>
        /// 创建一个新的
        /// </summary>
        /// <returns></returns>
        public XScope Clone()
        {
            string text = Element.ToString();
            var e = XElement.Parse(text);
            return new XScope(e);
        }
    }
}
